package core;

import static org.junit.Assert.*;

import java.util.Calendar;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import core.exception.IllegalAddException;

public class ProductTest 
{
	private Product product1;
	private Barcode barcode1;
	private Amount amt1;
	private Amount amt2;
	private Calendar beforeCal;
	private Calendar afterCal;
	
	@Before
	public void setUp() throws Exception 
	{
		barcode1 = new Barcode("123456789012", BarcodeType.PRODUCT);
		amt1 = new Amount(2.0F, UnitOfMeasurement.count);
		amt2 = new Amount (20, UnitOfMeasurement.fluid_ounces);
		beforeCal = Calendar.getInstance();
		product1 = new Product(barcode1, "desc", amt1, 2, 15);
		afterCal = Calendar.getInstance();
	}

	@After
	public void tearDown() throws Exception 
	{
		barcode1 = null;
		amt1 = null;
		amt2 = null;
		product1 = null;
		beforeCal = null;
		afterCal = null;
	}

	@Test
	public void testProductConstructorAndGetters() 
	{
		assertEquals(product1.getBarcode(), barcode1);
		assertTrue(product1.getDescription().equals("desc"));
		assertTrue(product1.getShelfLife() == 2);
		assertTrue(product1.getSize().equals(amt1));
		assertTrue(product1.getThreeMonthSupply() == 15);
	}

	@Test
	public void testCanCreate() 
	{
		//test the barcode validation
		assertFalse(Product.canCreate(null, "desc", amt1, 2, 15));
		Barcode barcode2 = new Barcode("42345678901", BarcodeType.ITEM);
		assertFalse(Product.canCreate(barcode2, "desc", amt1, 2, 15));
		
		//test the string validation
		assertFalse(Product.canCreate(barcode1, "", amt1, 2, 15));
		
		//test the amount validation
		assertFalse(Product.canCreate(barcode1, "desc", null, 2, 15));
		
		//test the shelflife validation
		assertFalse(Product.canCreate(barcode1, "desc", amt1, -1, 15));
		assertTrue(Product.canCreate(barcode1, "desc", amt1, 0, 15));
		
		//test the 3 month supply validation
		assertFalse(Product.canCreate(barcode1, "desc", amt1, 2, -1));
		assertTrue(Product.canCreate(barcode1, "desc", amt1, 2, 0));
		
		//test when all okay
		assertTrue(Product.canCreate(barcode1, "desc", amt1, 2, 15));
	}

	@Test
	public void testEditProduct() throws IllegalAddException 
	{
		Product product2 = new Product (barcode1, "test", amt2, 2000, 83);
		product1.editProduct(product2);
		assertTrue(product1.getBarcode() == barcode1);
		assertTrue(product1.getDescription().equals("test"));
		assertTrue(product1.getShelfLife() == 2000);
		assertTrue(product1.getSize().equals(amt2));
		assertTrue(product1.getThreeMonthSupply() == 83);
	}

	@Test
	public void testCanEdit() throws IllegalAddException 
	{
		assertFalse(product1.canEdit(null));
		Barcode barcode2 = new Barcode("023456789012", BarcodeType.PRODUCT);
		Product product2 = new Product(barcode2, "desc", amt1, 2, 15);
		assertFalse(product1.canEdit(product2));
		Product product3 = new Product (barcode1, "test", amt2, 2000, 83);
		assertTrue(product1.canEdit(product3));
	}

	@Test
	public void testSetDescription() 
	{
		String newDesc = "new description";
		product1.setDescription(newDesc);
		assertTrue(product1.getDescription().equals(newDesc));
		newDesc = "la dee dah";
		product1.setDescription(newDesc);
		assertTrue(product1.getDescription().equals(newDesc));
	}

	@Test
	public void testCanSetDescription() 
	{
		String newDesc = "something";
		assertTrue(product1.canSetDescription(newDesc));
		assertFalse(product1.canSetDescription(""));
	}

	@Test
	public void testSetSize() 
	{
		Amount amt2 = new Amount (20, UnitOfMeasurement.fluid_ounces);
		product1.setSize(amt2);
		assertEquals(amt2, product1.getSize());
		assertEquals(UnitOfMeasurement.fluid_ounces.toString(), product1.getUnitOfMeasurement());
		assertEquals(20, product1.getQuantityForOneUnit(), 0.001);
		amt2 = new Amount(1, UnitOfMeasurement.liters);
		product1.setSize(amt2);
		assertEquals(amt2, product1.getSize());
		assertEquals(UnitOfMeasurement.liters.toString(), product1.getUnitOfMeasurement());
		assertEquals(1, product1.getQuantityForOneUnit(), 0.001);
	}

	@Test
	public void testCanSetSize() 
	{
		assertFalse(product1.canSetSize(null));
		assertTrue(product1.canSetSize(amt2));
	}


	@Test
	public void testSetShelfLife() 
	{
		product1.setShelfLife(34);
		assertEquals(34, product1.getShelfLife());
		product1.setShelfLife(0);
		assertEquals(0, product1.getShelfLife());
	}

	@Test
	public void testCanSetShelfLife() 
	{
		assertFalse(product1.canSetShelfLife(-1));
		assertTrue(product1.canSetShelfLife(0));
		assertTrue(product1.canSetShelfLife(13));
	}

	@Test
	public void testSetThreeMonthSupply() 
	{
		product1.setThreeMonthSupply(17);
		assertEquals(17, product1.getThreeMonthSupply());
		product1.setThreeMonthSupply(0);
		assertEquals(0, product1.getThreeMonthSupply());
	}

	@Test
	public void testCanSetThreeMonthSupply() 
	{
		assertFalse(product1.canSetThreeMonthSupply(-1));
		assertTrue(product1.canSetThreeMonthSupply(0));
		assertTrue(product1.canSetThreeMonthSupply(1));
	}

	@Test
	public void testCompareTo() throws IllegalAddException 
	{
		Barcode barcode2 = new Barcode("023456789012", BarcodeType.PRODUCT);
		Barcode barcode3 = new Barcode("923456789012", BarcodeType.PRODUCT);
		
		Product product2 = new Product(barcode2, "desc", amt1, 2, 15);
		Product product3 = new Product(barcode3, "desc", amt1, 2, 15);
		
		assertTrue(barcode2.compareTo(barcode3) * product2.compareTo(product3) > 0);
		assertTrue(barcode3.compareTo(barcode2) * product3.compareTo(product2) > 0);
		assertTrue(barcode2.compareTo(barcode1) * product2.compareTo(product1) > 0);
		assertTrue(barcode1.compareTo(barcode3) * product1.compareTo(product3) > 0);
		assertTrue(barcode1.compareTo(barcode1) == 0);
	}

}
